home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / What's New? / Development Kits / Mac OS / USB DDK 1.4.6f4 / Examples / USBSampleStorageDriver / StorageClassDriver / StorageClassShim.c < prev    next >
Encoding:
Text File  |  2000-09-25  |  25.9 KB  |  805 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        StorageClassShim.c
  3.  
  4.     Contains:    USB Storage Class Shim
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1998-2000 by Apple Computer, Inc., all rights reserved.
  9. */
  10.  
  11. // Universal Headers
  12.  
  13. #include <Devices.h>
  14. #include <DriverGestalt.h>
  15. #include <DriverServices.h>
  16. #include <Folders.h>
  17. #include <MacTypes.h>
  18. #include <Resources.h>
  19. #include <USB.h>
  20.  
  21. // Project Headers
  22. #include "StorageClassShim.h"
  23. #include "StorageClassPublicAPI.h"
  24. #include "StorageClassShimDS.h"
  25. #include "StorageDeviceConfiguration.h"
  26.  
  27. // Enumerations for the range of Unittable entries
  28. // in which InstallDriverFromMemory will try to install the driver
  29. enum
  30. {
  31.     kUnitTableFloppyRefNum                = 4,
  32.     kUnitTableEntryStart                = 48,
  33.     kUnitTableDriverResource             = 128
  34. };
  35.  
  36.  
  37. // These are all variables that are global to the Shim
  38. static Boolean                     shimInFile;
  39. static FSSpec                    shimFSSpec;
  40. static UInt32                    gNotificationTokenCount = 0;
  41. static UInt32                    gNotificationToken[10] = {0,0,0,0,0,0,0,0,0,0};
  42. static IOCompletionUPP            gInitCompletionUPP = nil;
  43. static IOCompletionUPP            gDeviceInfoCompletionUPP = nil;
  44. static IOCompletionUPP            gTerminateCompletionUPP = nil;
  45.  
  46. // Here are all the prototypes for functions static to the shim
  47. static UInt32         MyUSBGetVersion(void);
  48. static void            myNotificationCallback (USBDeviceNotificationParameterBlock *pb);
  49. static void         HandleAddNotification( USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification );
  50. static void         HandleRemoveNotification( USBDeviceRef theDevRef, Boolean isDeviceNotification );
  51.  
  52. // Functions used by the shim to Install and Remove USB Expert notifications
  53. static Boolean         InstallUSBNotifications( void );
  54. static Boolean         RemoveUSBNotifications( void );
  55.  
  56. static OSStatus     ShimOpenDriver(USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification );
  57. static OSStatus     ShimCloseDriver(USBDeviceRef theDevRef);
  58.  
  59. // Internal Completion routines that have UPPs allocated.
  60. static void         InitializeCntrlCallCompletionProc( ParmBlkPtr paramBlock );
  61. static void             GetDeviceInfoCallCompletionProc( ParmBlkPtr paramBlock );
  62. static void         RetryUnitTableConfig( USBPB *usbPB);
  63. static void         TerminateCntrlCallCompletionProc( ParmBlkPtr paramBlock );
  64.  
  65. // Supporting functions
  66. static OSStatus     GetRegEntryIDForUSBReference( USBDeviceRef usbRefNum, USBDeviceRef    *parentsDeviceRef, RegEntryIDPtr regEntryIDPtr, Boolean isDeviceNotification );
  67.  
  68. #pragma mark --
  69. #pragma mark Code Fragment Manager Functions
  70. /******************************** Code Fragment Manager Functions ******************************************/
  71.  
  72. // This is the Code Fragment Initialize routine.  This is called by the Code Fragment Manager when
  73. // the code fragment containing the shim is loaded.  We use this function to save the the FSSpec 
  74. // for the file containing the shim and the Unit Table Driver.
  75. OSErr CFragInitRoutine(CFragInitBlockPtr initBlkPtr)
  76. {
  77.     shimInFile = false;
  78.     
  79.     if (CFragHasFileLocation(initBlkPtr->fragLocator.where))
  80.     {
  81.         shimInFile = true;
  82.         shimFSSpec = *(initBlkPtr->fragLocator.u.onDisk.fileSpec);            // save the FSSpec, in case we need it later
  83.     }
  84.     
  85.     return noErr;
  86. }
  87.  
  88. // This is the Code Fragment Terminate routine.  This is called by the Code Fragment Manager when
  89. // the code fragment containing the shim is being removed. 
  90. void CFragTermRoutine( void )
  91. {
  92.     RemoveUSBNotifications();
  93.     TerminateStorageDriverServices();
  94.     
  95.     // Free resources used by our UPPs.  Check to see if the are nil, if so no need to dispose.
  96.     if ( gInitCompletionUPP != nil )
  97.     {
  98.         DisposeRoutineDescriptor( gInitCompletionUPP );
  99.     }
  100.     
  101.     if ( gDeviceInfoCompletionUPP != nil )
  102.     {
  103.         DisposeRoutineDescriptor( gDeviceInfoCompletionUPP );
  104.     }
  105.     
  106.     if ( gTerminateCompletionUPP != nil )
  107.     {
  108.         DisposeRoutineDescriptor( gTerminateCompletionUPP );
  109.     }
  110. }
  111.  
  112. #pragma mark --
  113. #pragma mark USB Manager/Expert Functions
  114. /******************************** USB Manager/Expert Functions ******************************************/
  115. UInt32 MyUSBGetVersion(void)
  116. {
  117.     UInt32    version;
  118.     
  119.        if ((Ptr) USBGetVersion != (Ptr) kUnresolvedCFragSymbolAddress)
  120.               version = USBGetVersion();
  121.        else
  122.               version = 0;    // version of USB is less than 1.3
  123.        return version;
  124. }
  125.  
  126. // This is the initialize entry point to the shim.  This function is exported so that it can
  127. // be called when the shim is loaded.
  128. OSStatus USBShim( void )
  129. {
  130.     if ( MyUSBGetVersion() < kMinimumUSBMgrVersion )    
  131.     {
  132.         // This does not meet the minimum USB Manager version, leave now.
  133.         return noErr; // Is there an error that should be returned? Does the USB Expert check?
  134.     }
  135.  
  136.     gInitCompletionUPP = NewIOCompletionProc(InitializeCntrlCallCompletionProc);
  137.     gDeviceInfoCompletionUPP = NewIOCompletionProc(GetDeviceInfoCallCompletionProc);
  138.     gTerminateCompletionUPP = NewIOCompletionProc(TerminateCntrlCallCompletionProc);
  139.     
  140.     // The USB Manager looks to be the one we want, or can use, prepare for usage.
  141.     InitializeStorageDriverServices();
  142.     
  143.     // Install notifications last because we could get notified immediately
  144.     InstallUSBNotifications();
  145.     return noErr;
  146. }
  147.  
  148. #pragma mark --
  149. #pragma mark USB Notification Functions
  150. /******************************** USB Notification Functions ******************************************/
  151. // This is the notification routine that the Expert will call when a Mass Storage Device
  152. // has been attached to the USB or removed from the USB.
  153. void myNotificationCallback(USBDeviceNotificationParameterBlock *pb)
  154. {
  155.     Boolean isADeviceNotification = false;
  156.     
  157.     switch(pb->usbDeviceNotification)        // why were we notified?
  158.     {
  159.         case kNotifyAddDevice:                // because mass storage device appeared
  160.             isADeviceNotification = true;    // Set flag saying this is a device notification
  161.                                             // and then pass through to next case
  162.         case kNotifyAddInterface:            // because mass storage interface appeared
  163.         {    
  164.             HandleAddNotification(pb->usbDeviceRef, pb->usbVendor, pb->usbProduct, pb->usbSubClass, isADeviceNotification); 
  165.         }
  166.         break;
  167.             
  168.         case kNotifyRemoveDevice:            // because a mass storage device or interface disappeared
  169.             isADeviceNotification = true;    // Set flag saying this is a device notification
  170.                                             // and then pass through to next case
  171.         case kNotifyRemoveInterface:        // because a mass storage device or interface disappeared
  172.         {
  173.             HandleRemoveNotification( pb->usbDeviceRef, isADeviceNotification );
  174.         }
  175.         break;
  176.             
  177.         default:
  178.         {
  179.         }
  180.         break;
  181.     }
  182. }
  183.  
  184. void HandleAddNotification( USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass, Boolean isDeviceNotification )
  185. {
  186.     ShimOpenDriver(theDevRef, usbVendor, usbProduct, usbSubClass, isDeviceNotification); 
  187. }
  188.  
  189. void HandleRemoveNotification( USBDeviceRef theDevRef,  Boolean isDeviceNotification )
  190. {
  191. #pragma unused ( isDeviceNotification )
  192.     ShimCloseDriver( theDevRef );
  193. }
  194.  
  195. // This routine is used by the shim to install its USB notification procs
  196. Boolean InstallUSBNotifications( void )
  197. {
  198.     USBDeviceNotificationParameterBlock pb;
  199.  
  200.     // Setup notification for Mass Storage Class Devices
  201.     pb.usbDeviceNotification     = kNotifyAnyEvent;        // tell me about everything
  202.     pb.usbClass                 = kDriverClassID;        // tell me about the specified class
  203.     pb.usbSubClass                 = kDriverSubclassID;    // tell me about the specified subclass
  204.     pb.usbProtocol                 = kUSBAnyProtocol;        // tell me about all protocols for this vendor/product
  205.     pb.usbVendor                 = kDriverVendorID;        // Only notify me for this specific vendor
  206.     pb.usbProduct                 = kDriverProductID;        // and for this specific product
  207.     pb.result                     = noErr;
  208.     pb.callback                 = (USBDeviceNotificationCallbackProcPtr) &myNotificationCallback;        
  209.     pb.refcon                     = nil;
  210.      USBInstallDeviceNotification (&pb);    
  211.     if ( pb.result == noErr )
  212.     {
  213.         gNotificationToken[gNotificationTokenCount] = pb.token;
  214.         gNotificationTokenCount++;     // Zero based array,increment to get true count
  215.     }
  216.  
  217.     return true;
  218. }
  219.  
  220. // This routine is used by the shim to remove its USB notification procs
  221. Boolean RemoveUSBNotifications( void )
  222. {
  223.     while ( gNotificationTokenCount > 0 )
  224.     {
  225.         gNotificationTokenCount--;     // Zero based array, decrement the counter first
  226.         if ( gNotificationToken[gNotificationTokenCount] !=0 )
  227.         {
  228.             USBRemoveDeviceNotification( gNotificationToken[gNotificationTokenCount] );
  229.             gNotificationToken[gNotificationTokenCount]  = 0;
  230.         }
  231.     }
  232.  
  233.     return true;
  234. }
  235.  
  236. #pragma mark -- 
  237. #pragma mark Open Driver Functions
  238. static OSStatus SendInitializeControlCall (DriverInfoPtr currentDriveInfoPtr);
  239. static void SendGetDeviceInfoDriverGestaltCall (DriverInfoPtr currentDriveInfoPtr);
  240.  
  241. // This function is called by our notification routine to load a Unit Table driver when the device
  242. // we specified in our notification setup is attached
  243. OSStatus ShimOpenDriver(USBDeviceRef theDevRef, UInt16 usbVendor, UInt16 usbProduct, UInt8 usbSubClass,  Boolean isDeviceNotification )
  244. {
  245.     OSStatus            theErr = noErr;
  246.     Handle                hDrvrResource;
  247.     THz                    currentZone;
  248.     DriverRefNum        drvrRefNum;
  249.     void                *pTheStorageClassDispatchTable;
  250.     CFragSymbolClass    symClass;
  251.     CFragConnectionID    connID;
  252.     DriverInfoPtr        currentDriveInfoPtr;
  253.     RegEntryID             usbRegEntryID;
  254.     RegEntryIDPtr         usbRegEntryIDPtr;
  255.  
  256.     // We have been notified of a new device, check to see if we already 
  257.     // have installed a driver the USB Device Ref.
  258.     currentDriveInfoPtr = FindDriverInfoByUSBDeviceRef( theDevRef );
  259.     if ( currentDriveInfoPtr != nil )
  260.     {
  261.         // We already have a driver loaded for this device, return
  262.         return noErr;
  263.     }
  264.  
  265.     USBGetDriverConnectionID( &theDevRef, &connID );
  266.     
  267.     // Check if we have a driver for the subclass installed without the device
  268.     currentDriveInfoPtr = GetDriverInfoHeadPtr();
  269.     while ( currentDriveInfoPtr != nil )
  270.     {
  271.         if(( currentDriveInfoPtr->usbDeviceRef == 0 ) && (currentDriveInfoPtr->usbSubClass == usbSubClass )
  272.             && (currentDriveInfoPtr->usbVendor == usbVendor ) && (currentDriveInfoPtr->usbProduct == usbProduct ))
  273.         {
  274.             // We have found a driver candidate
  275.             drvrRefNum = currentDriveInfoPtr->drvrRefNum;
  276.             currentDriveInfoPtr->usbDeviceRef = theDevRef;
  277.             break;
  278.         }
  279.         
  280.         currentDriveInfoPtr = currentDriveInfoPtr->nextDriverInfo;
  281.     }
  282.  
  283.     // if the currentDriveInfoPtr is nil, we know that we don't have a DriveInfo element
  284.     // for this new device yet, let's build one
  285.     if ( currentDriveInfoPtr == nil )
  286.     {
  287.         short    oldResFileID = 0;
  288.  
  289.         SetResLoad(true);
  290.         oldResFileID = CurResFile();                                    // get the current resource file ID
  291.  
  292.         // No driver has been loaded for this USBDeviceRef, find the driver's 'ndrv' resource        
  293.         if (shimInFile)
  294.         {
  295.             short    myResFileID = 0;
  296.  
  297.             myResFileID = OpenShimResourceFork();
  298.             UseResFile(myResFileID);                                        // point at the shim file
  299.  
  300.             currentZone = GetZone ();
  301.             SetZone ( SystemZone() );
  302.             hDrvrResource = Get1Resource('ndrv', kUnitTableDriverResource);    // read in the driver from a ndrv resource
  303.             DetachResource(hDrvrResource);                                    // Detach the resource so it hangs around in the system heap
  304.             SetZone (currentZone);
  305.     
  306.             UseResFile(oldResFileID);                                        // point at the original file
  307.             CloseShimResourceFork();                                        // Make sure the resource file is closed
  308.         }
  309.  
  310.         // We have found the driver's 'ndrv' resource, install it into the UnitTable
  311.         if (hDrvrResource)
  312.         {
  313.             long                drvrSize;
  314.             Ptr                    pDrvrInMemory;
  315.             USBDeviceRef        parentsDeviceRef;
  316.     
  317.             // Lock the Driver Resource in memory
  318.             HLock(hDrvrResource);
  319.     
  320.             // Get the resource information needed to install the Driver
  321.             pDrvrInMemory = *hDrvrResource;
  322.             drvrSize = GetHandleSize(hDrvrResource);
  323.  
  324.             usbRegEntryIDPtr = &usbRegEntryID;
  325.             theErr = GetRegEntryIDForUSBReference( theDevRef, &parentsDeviceRef, usbRegEntryIDPtr, isDeviceNotification );
  326.             if ( theErr != noErr )
  327.             {
  328.                 usbRegEntryIDPtr = nil;
  329.             }
  330.             
  331.             // Check if this is a floppy subclass device
  332.             if( usbSubClass == kUSBStorageUFISubclass )
  333.             {
  334.                 // If a floppy subclass, try the traditional floppy UnitTable spot first
  335.                 theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, usbRegEntryIDPtr, kUnitTableFloppyRefNum, kUnitTableFloppyRefNum, &drvrRefNum);
  336.                 if ( theErr != noErr )
  337.                 {
  338.                     // We couldn't get the traditional spot, try normal range
  339.                     // We try from kUnitTableEntryStart to HighestUnitNumber+1 which will try all entries in the table and the are all full and
  340.                     // the table hasn't grown to its maximum size, trying a number bigger than HighestUnitNumber will force the table to grow.
  341.                     theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, usbRegEntryIDPtr, kUnitTableEntryStart, HighestUnitNumber()+1, &drvrRefNum);
  342.                 }
  343.             }
  344.             else
  345.             {
  346.                 // Install the driver
  347.                 // We try from kUnitTableEntryStart to HighestUnitNumber+1 which will try all entries in the table and the are all full and
  348.                 // the table hasn't grown to its maximum size, trying a number bigger than HighestUnitNumber will force the table to grow.
  349.                 theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, usbRegEntryIDPtr, kUnitTableEntryStart, HighestUnitNumber()+1, &drvrRefNum);
  350.             }
  351.             
  352.             if ( theErr != noErr )
  353.             {
  354.                 // The driver could not be loaded, the shim will return the error and abort the driver load
  355.                 return theErr;
  356.             }
  357.             
  358.             // Save the Driver refnum to remove the driver when the remove notification is recieved
  359.             currentDriveInfoPtr = AddDriverInfoPtr();
  360.             if (currentDriveInfoPtr == nil )
  361.             {
  362.                 // We couldn't get any memory, just bail for now.
  363.                 // Should probably figure a graceful way to handle this.
  364.                 return memFullErr;
  365.             }
  366.             
  367.             currentDriveInfoPtr->usbDeviceRef = theDevRef;
  368.             currentDriveInfoPtr->parentsDeviceRef = parentsDeviceRef;
  369.             currentDriveInfoPtr->usbSubClass = usbSubClass;
  370.             currentDriveInfoPtr->usbVendor = usbVendor;
  371.             currentDriveInfoPtr->usbProduct = usbProduct;
  372.             currentDriveInfoPtr->drvrRefNum = drvrRefNum;
  373.             currentDriveInfoPtr->drvrHndlInMemory = hDrvrResource;
  374.         }
  375.     }
  376.  
  377.     // Get the Storage class dispatch table 
  378.     currentZone = GetZone ();
  379.     SetZone ( SystemZone() );
  380.     
  381.     theErr = FindSymbol(connID, "\pTheStorageClassDispatchTable", (Ptr *)&pTheStorageClassDispatchTable, &symClass);
  382.     SetZone (currentZone);
  383.  
  384.     // If no error occured, pass the dispatch table pointer to the Driver
  385.     if (theErr == noErr)            
  386.     {
  387.         currentDriveInfoPtr->theSetupTable.usbDeviceRef = theDevRef;
  388.         currentDriveInfoPtr->theSetupTable.usbParentRef = currentDriveInfoPtr->parentsDeviceRef;
  389.         currentDriveInfoPtr->theSetupTable.usbSubClass = usbSubClass;
  390.         currentDriveInfoPtr->theSetupTable.usbVendor = usbVendor;
  391.         currentDriveInfoPtr->theSetupTable.usbProduct = usbProduct;
  392.         currentDriveInfoPtr->theSetupTable.shimDispatchTable = GetShimDispatchTablePtr();
  393.         currentDriveInfoPtr->theSetupTable.theStorageClassDispatchTable = pTheStorageClassDispatchTable;
  394.  
  395.  
  396.         theErr = SendInitializeControlCall ( currentDriveInfoPtr );
  397.     }
  398.     else
  399.     {
  400.         // We will get to this point if there was an error on either the FindSymbol call
  401.         // if an error occurs, we should remove the driver from the unittable
  402.         ShimCloseDriver(theDevRef);
  403.     }
  404.  
  405.     return theErr;
  406. }
  407.  
  408. OSStatus SendInitializeControlCall (DriverInfoPtr currentDriveInfoPtr)
  409. {
  410.     OSStatus                         theErr;
  411.     USBStorageClassSetupTablePtr     theSetupTable;
  412.  
  413.     theSetupTable = ¤tDriveInfoPtr->theSetupTable;
  414.  
  415.     // Set the Dispatch table so that the Unit Table driver can communicate with the class driver
  416.     BlockZero( ¤tDriveInfoPtr->controlPB, sizeof( CntrlParam ));
  417.     currentDriveInfoPtr->controlPB.ioCompletion = gInitCompletionUPP;
  418.     currentDriveInfoPtr->controlPB.ioVRefNum    = 0;
  419.     currentDriveInfoPtr->controlPB.ioCRefNum     = currentDriveInfoPtr->drvrRefNum;
  420.     currentDriveInfoPtr->controlPB.csCode         = kInitializeDeviceAccess;
  421.     *((UInt32 *) ¤tDriveInfoPtr->controlPB.csParam[0]) = (UInt32) theSetupTable;
  422.     theErr = PBControlAsync( (ParmBlkPtr) ¤tDriveInfoPtr->controlPB);
  423.     if ( theErr != noErr )
  424.     {
  425.         // An error occurred on the kInitializeDeviceAccess control 
  426.         // call and it couldn't be sent, there is nothing more that 
  427.         // can be done, so remove this driver from the UnitTable
  428.         ShimCloseDriver(currentDriveInfoPtr->usbDeviceRef);
  429.     }
  430.     
  431.     return theErr;
  432. }
  433.  
  434. void InitializeCntrlCallCompletionProc( ParmBlkPtr paramBlock )
  435. {
  436.     CntrlParam        *ourCntrlPB;
  437.     DriverInfoPtr     currentDriveInfoPtr;
  438.     OSStatus        theErr;
  439.  
  440.     ourCntrlPB = (CntrlParam *) paramBlock;
  441.     currentDriveInfoPtr = FindDriverInfoByDrvrRef( ourCntrlPB->ioCRefNum );
  442.     theErr = currentDriveInfoPtr->controlPB.ioResult;
  443.     if ( theErr == noErr )
  444.     {
  445.         if ( currentDriveInfoPtr->hasDialog == true )
  446.         {
  447.             RemoveNotificationDialog( currentDriveInfoPtr->drvrRefNum, currentDriveInfoPtr->messageNumber );
  448.         }
  449.  
  450.         SendGetDeviceInfoDriverGestaltCall ( currentDriveInfoPtr );
  451.     }
  452.     else if ( theErr == kClassNotConfiguredError )
  453.     {
  454.         BlockZero( ¤tDriveInfoPtr->configAgainPB, sizeof(USBPB));
  455.         
  456.         currentDriveInfoPtr->configAgainPB.pbLength = sizeof(USBPB);
  457.         currentDriveInfoPtr->configAgainPB.pbVersion = kUSBCurrentPBVersion;
  458.         currentDriveInfoPtr->configAgainPB.usbCompletion = &RetryUnitTableConfig;
  459.         currentDriveInfoPtr->configAgainPB.usbRefcon = (UInt32) currentDriveInfoPtr;
  460.         currentDriveInfoPtr->configAgainPB.usbReference = currentDriveInfoPtr->usbDeviceRef;
  461.         currentDriveInfoPtr->configAgainPB.usbReqCount = 100;
  462.         currentDriveInfoPtr->configAgainPB.usbFlags = kUSBTaskTimeFlag;
  463.         
  464.         theErr = USBDelay( ¤tDriveInfoPtr->configAgainPB );
  465.         if( theErr == kUSBPending )
  466.         {
  467.             theErr = noErr;
  468.         }
  469.     }
  470.     
  471.     if ( theErr != noErr )
  472.     {
  473.         // An error occurred on either kInitializeDeviceAccess control call
  474.         // or on the USBDelay call.  In either case, there is nothing that 
  475.         // can be done, so remove this driver from the UnitTable
  476.         ShimCloseDriver(currentDriveInfoPtr->usbDeviceRef);
  477.     }
  478. }
  479.  
  480. void SendGetDeviceInfoDriverGestaltCall (DriverInfoPtr currentDriveInfoPtr)
  481. {
  482.     // Get the Vendor Name of the device from the UnitTable driver
  483.     DriverGestaltParam            *theDGPB;
  484.     OSStatus                    theErr;
  485.     
  486.     theDGPB = (DriverGestaltParam *) ¤tDriveInfoPtr->controlPB;
  487.     
  488.     BlockZero(theDGPB, sizeof(DriverGestaltParam));
  489.     
  490.     theDGPB->ioCompletion     = (ProcPtr) gDeviceInfoCompletionUPP;
  491.     theDGPB->ioCRefNum         = currentDriveInfoPtr->drvrRefNum;
  492.     theDGPB->csCode         = kDriverGestaltCode;
  493.     theDGPB->driverGestaltSelector = kdgDeviceModelInfo;
  494.     theErr = PBStatusAsync((ParamBlockRec *) theDGPB);
  495.     if ( theErr != noErr )
  496.     {
  497.         // An error an we we not able to get the Device info data
  498.         // We must use the default data instead.
  499.         PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Device");
  500.     }
  501. }
  502.     
  503. void GetDeviceInfoCallCompletionProc( ParmBlkPtr paramBlock )
  504. {
  505.     DriverGestaltParam                        *theDGPB;
  506.     DriverInfoPtr                             currentDriveInfoPtr;
  507.     OSStatus                                theErr;
  508.     DriverGestaltDeviceModelInfoResponse    *theDeviceInfo;
  509.  
  510.     theDGPB = (DriverGestaltParam *) paramBlock;
  511.     currentDriveInfoPtr = FindDriverInfoByDrvrRef( theDGPB->ioCRefNum );
  512.     theErr = theDGPB->ioResult;
  513.     if( theErr == noErr )
  514.     {
  515.         theDeviceInfo = *(GetDriverGestaltDeviceModelInfoResponse(theDGPB));
  516.     }
  517.     else
  518.     {
  519.         theDeviceInfo = nil;
  520.     }
  521.     
  522.     if( (theDeviceInfo != nil) && ( theDeviceInfo->vendorName != nil ))
  523.     {
  524.         PStrCopy(currentDriveInfoPtr->VendorProductStr,theDeviceInfo->vendorName);
  525.         if( theDeviceInfo->productName != nil )
  526.         {
  527.             PStrCat(currentDriveInfoPtr->VendorProductStr,"\p ");
  528.             PStrCat(currentDriveInfoPtr->VendorProductStr,theDeviceInfo->productName);
  529.         }
  530.     }
  531.     else
  532.     {
  533.         BlockZero(theDGPB, sizeof(DriverGestaltParam));
  534.         
  535.         theDGPB->ioCRefNum = currentDriveInfoPtr->drvrRefNum;
  536.         theDGPB->csCode = kDriverGestaltCode;
  537.         theDGPB->driverGestaltSelector = kdgDeviceType;
  538.         theErr = PBStatusSync((ParamBlockRec *) theDGPB);
  539.         switch (GetDriverGestaltDevTResponse(theDGPB)->deviceType )
  540.         {
  541.             case kdgTapeType:
  542.             {
  543.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Tape Drive");
  544.             }
  545.             break;
  546.             
  547.             case kdgProcessorType:
  548.             {
  549.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Processor Device");
  550.             }
  551.             break;
  552.             
  553.             case kdgWormType:
  554.             {
  555.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown WORM Drive");
  556.             }
  557.             break;
  558.             
  559.             case kdgCDType:
  560.             {
  561.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown CD-ROM Drive");
  562.             }
  563.             break;
  564.             
  565.             case kdgFloppyType:
  566.             {
  567.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Floppy Disk Drive");
  568.             }
  569.             break;
  570.             
  571.             case kdgRemovableType:
  572.             {
  573.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Removable Media Drive");
  574.             }
  575.             break;
  576.             
  577.             case kdgDiskType:
  578.             {
  579.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Hard Disk Drive");
  580.             }
  581.             break;
  582.             
  583.             default:
  584.             {
  585.                 PStrCopy(currentDriveInfoPtr->VendorProductStr,"\pUnknown Device");
  586.             }
  587.         }
  588.     }
  589. }
  590.  
  591. void RetryUnitTableConfig( USBPB *usbPB)
  592. {
  593.     DriverInfoPtr                    currentDriveInfoPtr;
  594.     OSStatus                        theErr;
  595.  
  596.     currentDriveInfoPtr = (DriverInfoPtr) usbPB->usbRefcon;
  597.  
  598.     theErr = SendInitializeControlCall ( currentDriveInfoPtr );
  599. }
  600.  
  601.  
  602. #pragma mark -- 
  603. #pragma mark Close Driver Functions
  604. static OSStatus SendTerminateControlCall (DriverInfoPtr currentDriveInfoPtr);
  605.  
  606. OSStatus ShimCloseDriver(USBDeviceRef theDevRef)
  607. {
  608.     OSStatus            theErr = noErr;
  609.     DriverInfoPtr        currentDriveInfoPtr;
  610.  
  611.     currentDriveInfoPtr = FindDriverInfoByUSBDeviceRef( theDevRef );
  612.     if ( currentDriveInfoPtr == nil )
  613.     {
  614.         // There was no device with this USB Device Ref, just leave.
  615.         return noErr;
  616.     }
  617.     
  618.     if ( currentDriveInfoPtr->drvrRefNum == 0 )
  619.     {
  620.         // There was no UT driver loaded for this USB Device Ref, just leave.
  621.         return noErr;
  622.     }
  623.     
  624.     if ( currentDriveInfoPtr->hasDialog == true )
  625.     {
  626.         // This driver has a visible dialog, remove it
  627.         RemoveNotificationDialog( currentDriveInfoPtr->drvrRefNum, currentDriveInfoPtr->messageNumber );
  628.     }
  629.  
  630.     // We need to inform the UnitTable driver that it can no longer talk to the device.
  631.     // The UnitTable driver needs to allow the class driver to be removed.
  632.     theErr = SendTerminateControlCall ( currentDriveInfoPtr );
  633.  
  634.     return theErr;
  635. }
  636.  
  637. OSStatus SendTerminateControlCall ( DriverInfoPtr currentDriveInfoPtr )
  638. {
  639.     OSStatus                         theErr;
  640.  
  641.     // Set the Dispatch table so that the Unit Table driver can communicate with the class driver
  642.     BlockZero( ¤tDriveInfoPtr->controlPB, sizeof( CntrlParam ));
  643.     currentDriveInfoPtr->controlPB.ioVRefNum    = 0;
  644.     currentDriveInfoPtr->controlPB.ioCRefNum     = currentDriveInfoPtr->drvrRefNum;
  645.     currentDriveInfoPtr->controlPB.csCode         = kTerminateDeviceAccess;
  646.  
  647.     theErr = PBControlSync( (ParmBlkPtr) ¤tDriveInfoPtr->controlPB);
  648.     TerminateCntrlCallCompletionProc( (ParmBlkPtr) ¤tDriveInfoPtr->controlPB);
  649.     return noErr;
  650. }
  651.  
  652. void TerminateCntrlCallCompletionProc( ParmBlkPtr paramBlock )
  653. {
  654.     CntrlParam            *ourCntrlPB;
  655.     DriverInfoPtr         currentDriveInfoPtr;
  656.     OSStatus            theErr;
  657.     Boolean                doDriverRemoval = true;
  658.     VCBPtr                 vol;
  659.  
  660.     ourCntrlPB = (CntrlParam *) paramBlock;
  661.     currentDriveInfoPtr = FindDriverInfoByDrvrRef( ourCntrlPB->ioCRefNum );
  662.     theErr = currentDriveInfoPtr->controlPB.ioResult;
  663.     if ( theErr != noErr )
  664.     {
  665.         // The terminate control call failed, is there anything that 
  666.         // can be done at this point?
  667.         // We will try to unmount all volumes just in case we can
  668.         //return;
  669.     }
  670.     
  671.     vol = (VCBPtr) (GetVCBQHdr())->qHead;
  672.     while (vol)
  673.     {
  674.         // Check to see if this volume belongs to the driver
  675.         // that is being removed
  676.         if( vol->vcbDRefNum == currentDriveInfoPtr->drvrRefNum)
  677.         {
  678.             theErr = UnmountVol( nil, vol->vcbVRefNum );
  679.             // Check if unmount volume returns a file busy err
  680.             if (theErr == fBsyErr)
  681.             {
  682.                 doDriverRemoval = false;
  683.             }
  684.         }
  685.         
  686.         vol = (VCBPtr) vol->qLink;
  687.     }
  688.     
  689.     // if Do Removal is true, remove the drivers, else if Do Removal is false,
  690.     // display the reattach dialog box.
  691.     if ( doDriverRemoval == true )
  692.     {
  693.         theErr = RemoveDriver(currentDriveInfoPtr->drvrRefNum, false);
  694.         if ( theErr == noErr )
  695.         {
  696.             // The driver was successfully closed and removed,
  697.             // free all associated resources.
  698.             HUnlock( currentDriveInfoPtr->drvrHndlInMemory );
  699.             DisposeHandle( currentDriveInfoPtr->drvrHndlInMemory );
  700.             RemoveDriverInfoPtr( currentDriveInfoPtr );
  701.         }
  702.     }
  703.     else
  704.     {
  705.         vol = (VCBPtr) (GetVCBQHdr())->qHead;
  706.         
  707.         while (vol)
  708.         {
  709.             // Check to see if this volume belongs to the driver that is being removed
  710.             if( vol->vcbDRefNum == currentDriveInfoPtr->drvrRefNum)
  711.             {
  712.                 theErr = Eject( nil, vol->vcbVRefNum);
  713.             }
  714.             
  715.             vol = (VCBPtr) vol->qLink;
  716.         }
  717.  
  718.         // The device is already gone, clear the USB ref
  719.         currentDriveInfoPtr->usbDeviceRef = 0;
  720.         DisplayNotifcationDialog(currentDriveInfoPtr->drvrRefNum, kUSBStorageEventDeviceWasRemoved);
  721.     }
  722. }
  723.  
  724.  
  725. #pragma mark -- 
  726. #pragma mark Shim Support Functions
  727. /******************************** Shim Support Functions ******************************************/
  728. // These are the routines that the Shim needs to support its operations.  These includes initialization
  729. // routines, Unit Table driver matching and loading routines and shim termination routines.
  730.  
  731. // These two functions give us a convenient way for any part of the shim to open
  732. // and close its resource fork
  733. static int resOpenCount = 0;
  734. static short resFileRef = 0;
  735.  
  736. short OpenShimResourceFork( void )
  737. {
  738.     if (shimInFile)
  739.     {
  740.         if ( resOpenCount == 0 )
  741.         {
  742.             // If we have not already opened the file, open it now
  743.             resFileRef = FSpOpenResFile(&shimFSSpec, fsRdPerm);
  744.             if ( resFileRef !=0 )
  745.             {
  746.                 resOpenCount++;
  747.             }
  748.         }
  749.     }
  750.     else
  751.     {
  752.         resFileRef = 0;
  753.     }
  754.     
  755.     return resFileRef;
  756. }
  757.  
  758. void CloseShimResourceFork( void )
  759. {
  760.     if ( ( resOpenCount !=0 ) && ( resFileRef != 0 ))
  761.     {
  762.         resOpenCount--;
  763.     }
  764.     
  765.     if (( resOpenCount == 0 ) && ( resFileRef != 0 ))
  766.     {
  767.         CloseResFile(resFileRef);
  768.         resFileRef = 0;
  769.     }
  770. }
  771.  
  772. OSStatus GetRegEntryIDForUSBReference( USBDeviceRef usbRefNum, USBDeviceRef    *parentsDeviceRef, RegEntryIDPtr regEntryIDPtr, Boolean isDeviceNotification )
  773. {
  774.     OSStatus                 err = noErr;
  775.     RegEntryIter            cookie;
  776.     Boolean                    done;
  777.     
  778.     err = RegistryEntryIDInit(regEntryIDPtr);
  779.     if (err != noErr)
  780.     {
  781.         return err;
  782.     }
  783.         
  784.     err = RegistryEntryIterateCreate(&cookie);
  785.     if (err != noErr)
  786.     {
  787.         return err;
  788.     }
  789.  
  790.     if ( isDeviceNotification == true )
  791.     {
  792.         err = RegistryEntrySearch(&cookie, kRegIterDescendants, regEntryIDPtr, &done, "deviceRef", (const void *)&usbRefNum, (RegPropertyValueSize) sizeof(USBDeviceRef));
  793.         *parentsDeviceRef = 0;
  794.     }
  795.     else
  796.     {
  797.         RegPropertyValueSize    refPropSize = sizeof(USBDeviceRef);
  798.         
  799.         err = RegistryEntrySearch(&cookie, kRegIterDescendants, regEntryIDPtr, &done, "interfaceRef", (const void *)&usbRefNum, (RegPropertyValueSize) sizeof(USBDeviceRef));
  800.         err = RegistryPropertyGet( regEntryIDPtr, "parent-deviceRef", (void *) parentsDeviceRef, &refPropSize);
  801.     }
  802.     
  803.     RegistryEntryIterateDispose(&cookie);
  804.     return err;
  805. }